#pragma once
#include "gtest/gtest.h"
#include "DBManager/Database/DatabaseFactory.h"
#include "DBManager/DBServiceFactory.h"
#include "DBManager/IService/Input/Material/IIsotropicMaterialService.h"
#include "DBManager/IService/Input/Property/IPBARLService.h"
#include "DBManager/IService/Input/Property/IPBARService.h"
#include "DBManager/IService/Input/Property/IPBRSECTService.h"
#include "DBManager/IService/Input/Node/IPointService.h"
#include "DBManager/IService/Input/Partition/ISET1Service.h"
#include "DataStructure/Input/Node/PointData.h"
#include "DataStructure/Input/Partition/SET1Data.h"
#include "DataStructure/Input/Property/BeamSectionStandardTypes.h"
#include "../BarSectionParser.h"

using SG::DataStructure::Common::Id;
using SG::DataStructure::FEM::IsotropicMaterial;
using SG::DataStructure::FEM::BeamSectionStandardTypes;
using SG::DataStructure::FEM::PBARLData;
using SG::DataStructure::FEM::PBARData;
using SG::FEMSolver::Element::BarSectionParser;
using namespace SG::DBManager;

extern std::shared_ptr<DBServiceFactory> DB_SERVICEFACTORY;

class BarSectionParserTest : public ::testing::Test
{
public:
    static void SetUpTestSuite ()
    {
        DB_SERVICEFACTORY->ClearDatabase ();

        // 梁属性1, id为1，直接指定属性数值
        PBARData pBar;
        pBar.m_id  = 1;
        pBar.m_mId = 1;
        pBar.m_A   = 7.0;
        pBar.m_I1  = 7.145833;
        pBar.m_I2  = 2.333333;
        pBar.m_I12 = 0.0;
        pBar.m_J   = 6.003188;
        pBar.m_K1  = 0.8333333;
        pBar.m_K2  = 0.8333333;
        pBar.m_NSM = 0.0;
        pBar.SetStressPoints ({1.75, 1.0, -1.75, 1.0, -1.75, -1.0, 1.75, -1.0});
        DB_SERVICEFACTORY->get<IPBARService> ()->Add (pBar);

        // 梁属性2，id为2，使用标准形状指定属性
        PBARLData pBarL;
        pBarL.m_id  = 2;
        pBarL.m_mId = 1;
        pBarL.SetBeamSectionStandardTypes (BeamSectionStandardTypes::BEAMSECTYPE_BOX);
        pBarL.m_dimension = {4.0, 5.0, 2.0, 1.0};
        pBarL.m_nsm       = 0.0;
        DB_SERVICEFACTORY->get<IPBARLService> ()->Add (pBarL);

        // 材料1，id为1
        IsotropicMaterial material;
        material.m_id  = 1;
        material.m_E   = 70000.0;
        material.m_nu  = 0.3;
        material.m_rho = 2.7e-9;
        DB_SERVICEFACTORY->get<IIsotropicMaterialService> ()->Add (material);
    }
};

// 测试获取直接指定数值的梁属性
TEST_F (BarSectionParserTest, GetSectionProperty)
{
    // Test data
    BarSectionParser parser;
    Id               pId = 1;
    PBARData         propertyTest;
    parser.GetSectionProperty (DB_SERVICEFACTORY, pId, _OUT propertyTest);
    IsotropicMaterial materialTest;
    parser.GetMatrial (propertyTest.m_mId, _OUT materialTest);

    // Target data (property)
    PBARData propertyTarget;
    propertyTarget.m_id  = 1;
    propertyTarget.m_mId = 1;
    propertyTarget.m_A   = 7.0;
    propertyTarget.m_I1  = 7.145833;
    propertyTarget.m_I2  = 2.333333;
    propertyTarget.m_I12 = 0.0;
    propertyTarget.m_J   = 6.003188;
    propertyTarget.m_K1  = 0.8333333;
    propertyTarget.m_K2  = 0.8333333;
    propertyTarget.m_NSM = 0.0;
    propertyTarget.SetStressPoints ({1.75, 1.0, -1.75, 1.0, -1.75, -1.0, 1.75, -1.0});

    // Check property
    ASSERT_TRUE (propertyTarget == propertyTest);

    // Target data (material)
    IsotropicMaterial materialTarget;
    materialTarget.m_E   = 70000.0;
    materialTarget.m_nu  = 0.3;
    materialTarget.m_rho = 2.7e-9;

    // Check material
    ASSERT_TRUE (materialTarget == materialTest);
}

// 测试获取使用标准形状指定的梁属性
TEST_F (BarSectionParserTest, GetStandardSectionProperty)
{
    // Test data
    BarSectionParser parser;
    Id               pId = 2;
    PBARData         propertyTest;
    parser.GetSectionProperty (DB_SERVICEFACTORY, pId, _OUT propertyTest);

    // Target data
    PBARData propertyTarget;
    propertyTarget.m_id  = 2;
    propertyTarget.m_mId = 1;
    propertyTarget.m_A   = 18.0;
    propertyTarget.m_I1  = 41.5;
    propertyTarget.m_I2  = 26.0;
    propertyTarget.m_I12 = 0.0;
    propertyTarget.m_J   = 36.0;
    propertyTarget.m_K1  = 0.1111111;
    propertyTarget.m_K2  = 0.4444444;
    propertyTarget.m_NSM = 0.0;
    propertyTarget.SetStressPoints ({2.5, 2.0, -2.5, 2.0, -2.5, -2.0, 2.5, -2.0});

    // Check property
    ASSERT_TRUE (propertyTarget == propertyTest);
}

// 测试获取任意形状指定的梁属性
TEST (BarArbitrarySectionParserTest, GetArbitrarySectionProperty)
{   
    // 构建数据库
    DB_SERVICEFACTORY->ClearDatabase ();

    SG::DataStructure::FEM::PointData Point1;
    Point1.m_id = 111; Point1.m_X[0] = 0; Point1.m_X[1] = 0;
    DB_SERVICEFACTORY->get<IPointService> ()->Add (Point1);

    SG::DataStructure::FEM::PointData Point2;
    Point2.m_id = 112; Point2.m_X[0] = 20.0; Point2.m_X[1] = 0.0;
    DB_SERVICEFACTORY->get<IPointService> ()->Add (Point2);

    SG::DataStructure::FEM::PointData Point113;
    Point113.m_id = 113; Point113.m_X[0] = 20.0; Point113.m_X[1] = 19.4;
    DB_SERVICEFACTORY->get<IPointService> ()->Add(Point113);

    SG::DataStructure::FEM::PointData Point114;
    Point114.m_id = 114; Point114.m_X[0] = 0.0; Point114.m_X[1] = 19.4;
    DB_SERVICEFACTORY->get<IPointService> ()->Add(Point114);

    SG::DataStructure::FEM::PointData Point125;
    Point125.m_id = 125; Point125.m_X[0] = 1.0; Point125.m_X[1] = 1.0;
    DB_SERVICEFACTORY->get<IPointService> ()->Add(Point125);

    SG::DataStructure::FEM::PointData Point126;
    Point126.m_id = 126; Point126.m_X[0] = 10.0; Point126.m_X[1] = 1.0;
    DB_SERVICEFACTORY->get<IPointService> ()->Add(Point126);

    SG::DataStructure::FEM::PointData Point127;
    Point127.m_id = 127; Point127.m_X[0] = 10.0; Point127.m_X[1] = 18.4;
    DB_SERVICEFACTORY->get<IPointService> ()->Add(Point127);

    SG::DataStructure::FEM::PointData Point128;
    Point128.m_id = 128; Point128.m_X[0] = 1.0; Point128.m_X[1] = 18.4;
    DB_SERVICEFACTORY->get<IPointService> ()->Add(Point128);

    SG::DataStructure::FEM::PointData Point132;
    Point132.m_id = 132; Point132.m_X[0] = 11.0; Point132.m_X[1] = 1.0;
    DB_SERVICEFACTORY->get<IPointService> ()->Add(Point132);

    SG::DataStructure::FEM::PointData Point133;
    Point133.m_id = 133; Point133.m_X[0] = 19.0; Point133.m_X[1] = 1.0;
    DB_SERVICEFACTORY->get<IPointService> ()->Add(Point133);

    SG::DataStructure::FEM::PointData Point134;
    Point134.m_id = 134; Point134.m_X[0] = 19.0; Point134.m_X[1] = 18.4;
    DB_SERVICEFACTORY->get<IPointService> ()->Add(Point134);

    SG::DataStructure::FEM::PointData Point135;
    Point135.m_id = 135; Point135.m_X[0] = 11.0; Point135.m_X[1] = 18.4;
    DB_SERVICEFACTORY->get<IPointService> ()->Add(Point135);

    SG::DataStructure::FEM::SET1Data Section1;
    Section1.m_id = 111; Section1.m_gids = {111, 112, 113, 114};
    DB_SERVICEFACTORY->get<ISET1Service>()->Add(Section1);

    SG::DataStructure::FEM::SET1Data Section2;
    Section2.m_id = 122; Section2.m_gids = {128, 127, 126, 125, 128};
    DB_SERVICEFACTORY->get<ISET1Service>()->Add(Section2);
    
    SG::DataStructure::FEM::SET1Data Section3;
    Section3.m_id = 133; Section3.m_gids = {132, 133, 134, 135};
    DB_SERVICEFACTORY->get<ISET1Service>()->Add(Section3);

    IsotropicMaterial material;
    material.m_id  = 10;
    DB_SERVICEFACTORY->get<IIsotropicMaterialService> ()->Add (material);

    SG::DataStructure::FEM::PBRSECTData Pbrsect31;
    Pbrsect31.m_id = 31; Pbrsect31.m_MID = 10;Pbrsect31.m_FORM = 1; Pbrsect31.m_OUTP = 111;
    SG::DataStructure::FEM::PBRSECTData::section sect;
    sect.inps.push_back({0, 122});
    sect.inps.push_back({0, 133});
    Pbrsect31.m_sections.push_back(sect);
    DB_SERVICEFACTORY->get<IPBRSECTService>()->Add (Pbrsect31);

    // 计算结果
    PBARData property;
    BarSectionParser parser;
    parser.GetSectionProperty(DB_SERVICEFACTORY, 31, _OUT property);

    // 验证
    ASSERT_NEAR(property.m_A, 92.19999999999999, TOLERANCE);
    ASSERT_NEAR(property.m_I1, 4705.93896484375, 4705 * 1e-5);
    ASSERT_NEAR(property.m_I2, 4481.912109375, 4481 * 1e-5);
    ASSERT_NEAR(property.m_I12, 0, TOLERANCE);
    ASSERT_NEAR(property.m_J, 6734.27880859375, 6734 * 1e-3);
    ASSERT_NEAR(property.m_K1, 0.5601521134376526, 0.56 * 1e-3);
    ASSERT_NEAR(property.m_K2, 0.35838454961776733, 0.35838454961776733 * 1e-3);
}